#include "Map.h"
#include "SentinelBridgeSpace.h"
#include "PortalOfPowerSpace.h"

#include "Character\PlayerCharacter.h"
#include <qlayoutitem.h>
#include <iostream>
#include <fstream>
#include <string>
#include <Windows.h>
#include <qcoreapplication.h>
using namespace std;

namespace talisman_map
{
	Map::Map(PlayerCharacter * iPlayer, PositionKeeper * iPositionKeeper, QWidget * parent) : QWidget(parent), 
		background(0),
		layout(0),
		mPositionKeeper(iPositionKeeper),
		mPlayer(iPlayer),
		mInitOk(false)
	{
		setFixedSize(800, 800);
		background = new QImage();
		background->load("Images\\map3.gif");
		layout = new QGridLayout(this);

	}

	Map::~Map()
	{
		if(0 != background)
			delete background;
		if(0 != layout)
			delete layout;
	}

	void Map::updateContents(void)
	{
		if(!mInitOk)
			return;

		int i = 0;
		int j = 0;
		int di = 0; 
		int dj = 1;
		int coil = 0;
		int w = 5;
		int h = 6;

		bool wLoopComplete = false;
		for (Space * sp = mOuterRegion.getStartSpace(); !wLoopComplete;)
		{

			if( mPositionKeeper->getCharacterLocation(mPlayer) == sp)
			{
				sp->setVisible(false);

				layout->addWidget(mPlayer, i, j,1,1);
			}
			else
			{
				sp->setVisible(true);
			}

			i+=di;
			j+=dj;

			if (j == (w-coil) && dj == 1)
			{
				dj = 0;
				di = 1;
			}
			else if (j == coil && dj == -1)
			{
				dj = 0;
				di = -1;
			}
			else if (i == (h-coil) && di == 1)
			{
				di = 0;
				dj = -1;
			}
			else if (i == coil && di == -1)
			{
				dj = 1;
				di = 0;
			}

			if (sp == mOuterRegion.getStartSpace()->getPrevSpace())
			{
				coil++;
				i=coil;
				j=coil;
				di = 0;
				dj = 1;
				sp = mMiddleRegion.getStartSpace();
			}
			else if (sp == mMiddleRegion.getStartSpace()->getPrevSpace())
			{
				coil++;
				i=coil;
				j=coil;
				di = 0;
				dj = 1;
				sp = mInnerRegion.getStartSpace();
			}
			else if (sp == mInnerRegion.getStartSpace()->getPrevSpace())
			{
				wLoopComplete=true;
			}
			else
			{ 
				sp = sp->getNextSpace();
			}
		}
	}

	void Map::setup(void)
	{
		if(!mInitOk)
			return;

		layout->setContentsMargins(30, 30, 30, 30);
		//layout->setMargi

		// Add outer region fields
		int i = 0;
		int j = 0;
		int di = 0; 
		int dj = 1;
		int coil = 0;
		int w = 5;
		int h = 6;

		for (int k = 0; k < h; ++k)
			layout->setRowMinimumHeight(k, 100);
		for (int k = 0; k < w; ++k)
			layout->setColumnMinimumWidth(k, 100);

		bool wLoopComplete = false;
		for (Space * sp = mOuterRegion.getStartSpace(); !wLoopComplete;)
		{
			layout->addWidget(sp, i, j,1,1, Qt::AlignLeft);
			i+=di;
			j+=dj;

			if (j == (w-coil) && dj == 1)
			{
				dj = 0;
				di = 1;
			}
			else if (j == coil && dj == -1)
			{
				dj = 0;
				di = -1;
			}
			else if (i == (h-coil) && di == 1)
			{
				di = 0;
				dj = -1;
			}
			else if (i == coil && di == -1)
			{
				dj = 1;
				di = 0;
			}

			if (sp == mOuterRegion.getStartSpace()->getPrevSpace())
			{
				coil++;
				i=coil;
				j=coil;
				di = 0;
				dj = 1;
				sp = mMiddleRegion.getStartSpace();
			}
			else if (sp == mMiddleRegion.getStartSpace()->getPrevSpace())
			{
				coil++;
				i=coil;
				j=coil;
				di = 0;
				dj = 1;
				sp = mInnerRegion.getStartSpace();
			}
			else if (sp == mInnerRegion.getStartSpace()->getPrevSpace())
			{
				wLoopComplete=true;
			}
			else
			{ 
				sp = sp->getNextSpace();
			}
		}
	}

	void Map::paintEvent(QPaintEvent *event)
	{
		QPainter qpainter(this);
		qpainter.drawImage(0, 0, *background);
	}

	void Map::setPlayer(PlayerCharacter * iPlayer)
	{
		if (layout != 0 )
		{
			QLayoutItem* item;
			while ( ( item = layout->takeAt( 0 ) ) != NULL )
			{
				if (item->widget() == mPlayer)
				{
					delete item->widget();
					delete item;
					break;
				}
			}
		}
		mPlayer = iPlayer;
		updateContents();
	}

	// Initializes the map from the file
	void Map::init(std::string iMapConfigFileName)
	{

		SentinelBridgeSpace * wSentinelBridgeCellInOuterRegion = new SentinelBridgeSpace();
		SentinelBridgeSpace * wSentinelBridgeCellInMiddleRegion = new SentinelBridgeSpace();
		wSentinelBridgeCellInOuterRegion->setSentinelBridgeOtherEnd(wSentinelBridgeCellInMiddleRegion);
		wSentinelBridgeCellInMiddleRegion->setSentinelBridgeOtherEnd(wSentinelBridgeCellInOuterRegion); // WARNING! cyclic referencing, it's up to the cells to clear up their pointers!
		PortalOfPowerSpace * wPortalOfPowerCellInInnerRegion = new PortalOfPowerSpace();
		PortalOfPowerSpace * wPortalOfPowerCellInMiddleRegion = new PortalOfPowerSpace();

		wPortalOfPowerCellInInnerRegion->setPortalOfPowerOtherEnd(wPortalOfPowerCellInMiddleRegion);
		wPortalOfPowerCellInMiddleRegion->setPortalOfPowerOtherEnd(wPortalOfPowerCellInInnerRegion); // WARNING! cyclic referencing, it's up to the cells to clear up their pointers!

		mInitOk = true;

		string prefSpace = "Space:";
		string prefOuter = "OuterRegion:";
		string prefMiddle = "MiddleRegion:";
		string prefInner = "InnerRegion:";
		string prefBridge = "Bridge:";
		string prefPortal = "Portal:";
		int regionIndex = 0; // start with outer
		vector<vector<string>> spaces;
		vector<string> outerSpaces;
		vector<string> middleSpaces;
		vector<string> innerSpaces;
		spaces.push_back(outerSpaces);
		spaces.push_back(middleSpaces);
		spaces.push_back(innerSpaces);

		string line;
		ifstream myfile (iMapConfigFileName);
		if (myfile.is_open())
		{
			while ( myfile.good() )
			{
				getline (myfile,line);
				if(pref(line, prefOuter))
					regionIndex = 0; // Outer
				else if (pref(line, prefMiddle))
					regionIndex = 1; // middle
				else if(pref(line, prefInner))
					regionIndex = 2; // inner
				else if (pref(line, prefSpace))
					spaces[regionIndex].push_back(line.substr(prefSpace.size()));
				else if (pref(line, prefBridge) && regionIndex == 0)
					wSentinelBridgeCellInOuterRegion->setDescription(line.substr(prefBridge.size()));
				else if (pref(line, prefBridge) && regionIndex == 1)
					wSentinelBridgeCellInMiddleRegion->setDescription(line.substr(prefBridge.size()));
				else if (pref(line, prefPortal) && regionIndex == 2)
					wPortalOfPowerCellInInnerRegion->setDescription(line.substr(prefPortal.size()));
				else if (pref(line, prefPortal) && regionIndex == 1)
					wPortalOfPowerCellInMiddleRegion->setDescription(line.substr(prefPortal.size()));
				else
					throw "Couldn't initialize the map - the file has an incorrect format.";
			}
			myfile.close();
		}
		else throw "Couldn't initialize the map - the file doesn't exist or can't be read."; 

		mOuterRegion = OuterRegion();
		mOuterRegion.generateRegion(wSentinelBridgeCellInOuterRegion, spaces[0]);
		mMiddleRegion.generateRegion(wSentinelBridgeCellInMiddleRegion, wPortalOfPowerCellInMiddleRegion,  spaces[1]);
		mInnerRegion.generateRegion(wPortalOfPowerCellInInnerRegion, spaces[2]);

	}

	bool Map::pref(string str, string pref) const
	{
		return (str.compare(0, pref.size(), pref) == 0);
	}
}
